package net.araim.bbingo.activity;

import java.util.Date;
import java.util.HashMap;

import net.araim.bbingo.BingoTextView;
import net.araim.bbingo.R;
import net.araim.bbingo.Settings;
import net.araim.bbingo.db.BingoDB;
import net.araim.bbingo.dialogs.MainMenuDialog;
import net.araim.bbingo.dialogs.ShameDialog;
import net.araim.bbingo.dialogs.WinnerDialog;
import net.araim.bbingo.interfaces.IDialogDismissListener;
import net.araim.bbingo.interfaces.IDialogOptionSelectedListener;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Typeface;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Animation.AnimationListener;
import android.widget.LinearLayout;

public class CorporateBingo extends Activity implements IDialogOptionSelectedListener, IDialogDismissListener {

	public final static String LOGTAG = "CORPBINGO";

	private final static int DIALOG_MAIN = 1;
	private final static int DIALOG_SHAME = 2;
	private final static int DIALOG_WIN = 3;

	private LinearLayout ll = null;
	private Settings s;
	private BingoDB db = null;
	private Date startDate = null;
	private boolean gameInProgress = false;

	public boolean isGameInProgress() {
		return gameInProgress;
	}

	private String[] texts = null;

	private void shuffle() {
		texts = db.getAllTexts();
		selects = new boolean[36];
		java.util.Random r = new java.util.Random();
		String s = "";
		for (int a = 0; a < texts.length; a++) {
			int i = r.nextInt(texts.length);
			int j = r.nextInt(texts.length);
			s = texts[i];
			texts[i] = texts[j];
			texts[j] = s;
		}

	}

	private final Handler uiThreadCallback = new Handler();
	private Runnable runInUIThread;

	private BingoTextView[][] sheet = new BingoTextView[6][6];
	private boolean selects[] = new boolean[36];

	private void CreateSheet() {
		int size = s.getSize();
		HashMap<String, BingoTextView> map = new HashMap<String, BingoTextView>();

		Typeface font = Typeface.createFromAsset(this.getAssets(), "fonts/LiberationSans-Bold.ttf");

		if (ll != null) {
			ll.removeAllViews();

		}

		ll = new LinearLayout(this);

		ll.setOrientation(LinearLayout.VERTICAL);
		LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
		ll.setLayoutParams(lp);

		for (int a = 0; a < size; a++) {
			LinearLayout inner = new LinearLayout(this);
			if (a == 0) {
				inner.setPadding(0, 1, 0, 0);
			}
			inner.setOrientation(LinearLayout.HORIZONTAL);
			ll.setWeightSum(size);
			inner.setWeightSum(size);
			ll.addView(inner, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT, 1f));
			for (int b = 0; b < size; b++) {
				LinearLayout innerinner = new LinearLayout(this);
				innerinner.setBackgroundColor(Color.WHITE);
				innerinner.setPadding(1, 1, 1, 1);
				inner.addView(innerinner, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT, 1f));
				BingoTextView tv = new BingoTextView(this);

				tv.setPadding(1, 1, 1, 1);
				tv.setTextSize(11f);
				tv.setTextColor(Color.LTGRAY);

				tv.setText(texts[(a * size + b) % texts.length]);
				map.put(tv.getText().toString(), tv);
				tv.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
				tv.setGravity(Gravity.CENTER);
				tv.setClickable(true);

				tv.setOnClickListener(new BingoClickListener());
				tv.setBackgroundColor(Color.BLACK);
				tv.setTypeface(font);
				if (selects[(a * size + b) % selects.length]) {
					tv.setSelected(true);
					tv.check();
					tv.setBackgroundColor(Color.WHITE);
					tv.setTextColor(Color.BLACK);
					innerinner.setBackgroundColor(Color.BLACK);
				}
				sheet[a][b] = tv;
				innerinner.addView(tv);

			}
		}
		setContentView(ll);
	}

	private void confirmExit() {
		new AlertDialog.Builder(this).setTitle(R.string.ExitConfirmTitle).setMessage(R.string.ExitConfirmMessage).setPositiveButton(
				R.string.Yes, new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						CorporateBingo.this.finish();
					}
				}).setNegativeButton(R.string.No, null).show();
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK) {
			if (gameInProgress) {
				confirmExit();
				return true;
			} else {
				finish();
				return true;
			}
		}
		return super.onKeyDown(keyCode, event);
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		outState.putStringArray("BullshitTexts", texts);
		outState.putBooleanArray("BullshitSelects", selects);
		outState.putBoolean("BullshitInProgress", gameInProgress);
		if (startDate != null) {
			outState.putLong("BullshitStartDate", startDate.getTime());
		}
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
	}

	@Override
	protected void onRestoreInstanceState(Bundle savedInstanceState) {
		super.onRestoreInstanceState(savedInstanceState);
		onCreate(savedInstanceState);
	}

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		if (savedInstanceState == null) {
			requestWindowFeature(Window.FEATURE_NO_TITLE);
		}

		db = new BingoDB(this);
		texts = db.getAllTexts();
		s = Settings.getInstance(getApplicationContext());

		// helps to initialize the media player
		MediaPlayer.create(CorporateBingo.this, R.raw.bingo2);

		if (savedInstanceState == null) {
			shuffle();
			showDialog(DIALOG_MAIN);
		} else {
			texts = savedInstanceState.getStringArray("BullshitTexts");
			selects = savedInstanceState.getBooleanArray("BullshitSelects");
			long l = savedInstanceState.getLong("BullshitStartDate", 0);
			gameInProgress = savedInstanceState.getBoolean("BullshitInProgress", false);
			if (l == 0) {
				startDate = null;
			} else {
				startDate = new Date(l);
			}
		}

		try {
			CreateSheet();
			runInUIThread = new Runnable() {
				public void run() {
					if (s.isSoundOn()) {
						try {
							final MediaPlayer bingo = MediaPlayer.create(CorporateBingo.this, R.raw.bingo2);
							bingo.start();
							bingo.setOnCompletionListener(new OnCompletionListener() {
								public void onCompletion(MediaPlayer mp) {
									bingo.release();
								}
							});
						} catch (Exception e) {
							Log.e(CorporateBingo.LOGTAG, "Error playing sound : " + e.toString());
						}
					}
					// TODO: register stats
					showDialog(DIALOG_WIN);
					gameInProgress = false;
				}
			};
		} catch (Exception e) {
			Log.e(LOGTAG, e.toString());
		}
	}

	@Override
	protected Dialog onCreateDialog(int id) {
		switch (id) {
		case DIALOG_MAIN:
			MainMenuDialog mmd = new MainMenuDialog(this);
			mmd.setOnOptionSelectedListener(this);
			return mmd;
		case DIALOG_SHAME:
			ShameDialog sd = new ShameDialog(this, db);
			sd.setDialogDismissListener(this);
			return sd;
		case DIALOG_WIN:
			WinnerDialog wd = new WinnerDialog(this, startDate);
			wd.setDialogDismissListener(this);
			return wd;
		default:
			return null;
		}
	}

	public void setTexts() {
		int size = s.getSize();
		for (int a = 0; a < size; a++) {
			LinearLayout inner = (LinearLayout) ll.getChildAt(a);
			for (int b = 0; b < size; b++) {
				LinearLayout wrapper = (LinearLayout) inner.getChildAt(b);
				BingoTextView btv = (BingoTextView) wrapper.getChildAt(0);
				btv.setText((texts[(a * size + b) % texts.length]));
				btv.uncheckAndReset();
			}
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// TODO change to IDS, move texts to strings
		super.onCreateOptionsMenu(menu);
		menu.add("Restart");
		menu.add("Back to Menu");
		menu.add("Close");

		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// TODO go for IDs
		super.onOptionsItemSelected(item);
		if (item.getTitle().equals("Restart")) {
			shuffle();
			selects = new boolean[36];
			setTexts();
		} else if (item.getTitle().equals("Close")) {
			confirmExit();
		} else if (item.getTitle().equals("Back to Menu")) {
			new AlertDialog.Builder(this).setTitle(R.string.ExitMenuConfirmTitle).setMessage(R.string.ExitMenuConfirmMessage)
					.setPositiveButton(R.string.Yes, new DialogInterface.OnClickListener() {
						public void onClick(DialogInterface dialog, int which) {
							shuffle();
							selects = new boolean[36];
							setTexts();
							showDialog(DIALOG_MAIN);
						}
					}).setNegativeButton(R.string.No, null).show();

		} else {
			return false;
		}
		return true;
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if (requestCode == 1234) {
			try {
				CreateSheet();
			} catch (Exception e) {
				Log.e(LOGTAG, e.toString());
			}
		} else if (requestCode == 4321) {
			try {
				shuffle();
				CreateSheet();
				showDialog(DIALOG_MAIN);
			} catch (Exception e) {
				Log.e(LOGTAG, e.toString());
			}

		}
	}

	private class BingoClickListener implements OnClickListener {

		public void onClick(View v) {
			final int size = s.getSize();
			for (int a = 0; a < size; a++) {
				for (int b = 0; b < size; b++) {
					BingoTextView w = sheet[a][b];
					if (w.getText().equals(((BingoTextView) v).getText())) {
						if (w.isChecked()) {
							w.uncheck();
							selects[a * size + b] = false;
							if (s.isSoundOn()) {
								try {
									final MediaPlayer fall = MediaPlayer.create(CorporateBingo.this, R.raw.beepfalling);
									fall.start();
									fall.setOnCompletionListener(new OnCompletionListener() {
										public void onCompletion(MediaPlayer mp) {
											fall.release();
										}
									});
								} catch (Exception e) {
									Log.e(CorporateBingo.LOGTAG, "Error playing sound : " + e.toString());
								}
							}
						} else {
							w.check();
							selects[a * size + b] = true;
							if (s.isSoundOn()) {
								try {
									final MediaPlayer rise = MediaPlayer.create(CorporateBingo.this, R.raw.beeprising);
									rise.start();
									rise.setOnCompletionListener(new OnCompletionListener() {
										public void onCompletion(MediaPlayer mp) {
											rise.release();
										}
									});

								} catch (Exception e) {
									Log.e(CorporateBingo.LOGTAG, "Error playing sound : " + e.toString());
								}

							}
						}
						Animation anim = new AlphaAnimation(1f, 0f);
						anim.setInterpolator(new DecelerateInterpolator());
						anim.setDuration(100);
						anim.setAnimationListener(new MyTextViewAnimationListener((BingoTextView) w));
						w.startAnimation(anim);
					}
				}
			}

			new Thread() {
				@Override
				public void run() {
					boolean across1 = true;
					boolean across2 = true;
					int[] res = new int[size];
					for (int a = 0; a < size; a++) {
						for (int b = 0; b < size; b++) {
							if (sheet[a][b].isChecked()) {
								res[a] += (int) Math.pow(2, b);
							} else {
								// left top to right bottom
								if (a == b) {
									across1 = false;
								}
								// left bottom to right top
								if (a == size - b - 1) {
									across2 = false;
								}
							}
						}
					}
					int result = res[0];
					for (int i = 1; i < size; i++) {
						result &= res[i];
					}
					if (result > 0 || across1 || across2) {
						uiThreadCallback.post(runInUIThread);
					} else {
						for (int a = 0; a < size; a++) {
							if (res[a] == (Math.pow(2, size) - 1)) {
								uiThreadCallback.post(runInUIThread);
							}
						}
					}

				}
			}.start();

		}

	}

	public void onOptionSelected(DialogInterface dialog, int optionId) {
		switch (optionId) {
		case R.id.MenuExitButton:
			finish();
			return;
		case R.id.MenuStartButton:
			shuffle();
			CreateSheet();
			dismissDialog(DIALOG_MAIN);
			startDate = new Date();
			gameInProgress = true;
			return;
		case R.id.MenuOptionsButton:
			Intent i = new Intent(this, net.araim.bbingo.activity.SettingsScreen.class);
			startActivityForResult(i, 1234);
			return;
		case R.id.MenuShameButton:
			dismissDialog(DIALOG_MAIN);
			showDialog(DIALOG_SHAME);
			return;
		case R.id.MenuHelpButton:
			dismissDialog(DIALOG_MAIN);
			Intent i2 = new Intent(this, net.araim.bbingo.activity.HelpActivity.class);
			startActivityForResult(i2, 4321);
			return;
		}
	}

	public void notifyDismiss(Dialog d, int reason) {
		if (d instanceof ShameDialog) {
			if (reason == ShameDialog.DISMISS_USER) {
				showDialog(DIALOG_MAIN);
			}
		}
		if (d instanceof WinnerDialog) {
			shuffle();
			CreateSheet();
			showDialog(DIALOG_MAIN);
			if (reason == WinnerDialog.DISMISS_SAVE) {
				WinnerDialog result = (WinnerDialog) d;
				if (result.isSave()) {
					db.saveResult(result.getMeetingName(), startDate, result.getEnd());
				}
			}
		}
	}

	private class MyTextViewAnimationListener implements AnimationListener {

		private BingoTextView v = null;

		public MyTextViewAnimationListener(BingoTextView w) {
			v = w;
		}

		public void onAnimationEnd(Animation animation) {
			if (v.isChecked()) {
				// v.check();
				v.setBackgroundColor(Color.WHITE);
				v.setTextColor(Color.BLACK);
				((View) v.getParent()).setBackgroundColor(Color.BLACK);
			} else {
				// v.uncheck();
				v.setBackgroundColor(Color.BLACK);
				v.setTextColor(Color.LTGRAY);
				((View) v.getParent()).setBackgroundColor(Color.WHITE);
			}
		}

		public void onAnimationRepeat(Animation animation) {
		}

		public void onAnimationStart(Animation animation) {

		}
	}

}